import java.util.concurrent.locks.ReentrantLock;

public class ThreadDemo2 {
    public static void main(String[] args) {
//        MyRunnable4 myRunnable4 = new MyRunnable4();
//        Thread thread1 = new Thread(myRunnable4);
//        Thread thread2 = new Thread(myRunnable4);
//        thread1.start();
//        thread2.start();

        MyRunnable5 myRunnable5 = new MyRunnable5();
        Thread thread3 = new Thread(myRunnable5);
        Thread thread4 = new Thread(myRunnable5);
        thread3.start();
        thread4.start();
    }
}

//同步：在任何时刻，最多有一个线程访问，保证数据的完整性。
//在持有锁的时候，不要对其他对象调用其同步方法，否则可能产生死锁。
class MyRunnable4 implements Runnable {

    //售票
    private int ticket = 10;

    @Override
    public void run() {
        for (int i = 0; i < 300; i++) {
            if (ticket > 0) {
                ticket--;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("您购买的票剩余" + ticket + "张");
            }
        }
    }
}

//同步方法一：同步代码块
//对于代码块，对象锁即指synchronized(abc)中的abc；
class MyRunnable5 implements Runnable {

    //任意的对象作为同步锁，把MyRunnable5对象锁住，即锁住了MyRunnable5 myRunnable5 = new MyRunnable5();
    private Object obj = new Object();
    //售票
    private int ticket = 10;

    @Override
    public void run() {
        for (int i = 0; i < 300; i++) {
            //同步锁为该对象
            //也可同步对象obj，写成：synchronized (obj)
            synchronized (this) {
                if (ticket > 0) {
                    ticket--;
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("您购买的票剩余" + ticket + "张");
                }
            }
        }
    }

    //同步方法二：同步方法,同步的对象是当前对象，this。
    //对于一个成员方法加synchronized关键字，这实际上是以这个成员方法所在的对象本身作为对象锁。每个线程持有自己线程对象的那个对象锁。
    //将同步方法替换synchronized(){}代码块即可
    private synchronized void method() {
        if (ticket > 0) {
            ticket--;
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("您购买的票剩余" + ticket + "张");
        }
    }

    //同步方法三：Lock(ReentrantLock),可以在想要控制的地方同步
    //先定义一个互斥锁
    ReentrantLock reentrantLock = new ReentrantLock();

    private void method2() {
        //上锁
        reentrantLock.lock();

        //加try catch finally保证一定释放，防止死锁。
        try {
            if (ticket > 0) {
                ticket--;
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("您购买的票剩余" + ticket + "张");
            }
        } finally {
            //解锁
            reentrantLock.unlock();
        }
    }
}
